/*************************************************
 * 
 * Copyright by Bruno Eberhard
 * 
 * Created on 29.07.2005
 *
 *************************************************/
package fightplan.views.tables;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;

import com.jgoodies.binding.value.ValueHolder;
import com.jgoodies.binding.value.ValueModel;

import fightplan.actions.UndoRedoManager;
import fightplan.actions.UndoRedoManagerProvider;
import fightplan.bindx.GObservableList;
import fightplan.business.Category;
import fightplan.business.Fight;
import fightplan.business.FightEntry;
import fightplan.business.ModifiableFighterProvider;
import fightplan.business.Plan;
import fightplan.business.Sheet;
import fightplan.business.Tournament;
import fightplan.core.FPExceptionHandler;
import fightplan.core.Style;
import fightplan.persistence.FilePersistence;
import fightplan.print.DrawingPrintable;
import fightplan.views.MainView;

@SuppressWarnings("serial")
public class SheetsTable extends JPanel implements PropertyChangeListener, UndoRedoManagerProvider {
	private JTable table;

	private SheetsTableModel tableModel;

	private ValueModel tournamentModel;

	private ValueModel selectedCategory;

	public SheetsTable(ValueModel tournamentModel) {
		super(new BorderLayout());

		this.tournamentModel = tournamentModel;
		tableModel = new SheetsTableModel((Tournament) tournamentModel.getValue());
		tournamentModel.addValueChangeListener(this);

		selectedCategory = new ValueHolder(null);

		table = new JTable(tableModel);
		table.setRowHeight(20);
		table.putClientProperty(fightplan.actions.SelectAllAction.MENU_CONTROLLED, Boolean.TRUE);

		JScrollPane scrollPane = new JScrollPane(table);
		scrollPane.setPreferredSize(new Dimension(5000, 5000));
		scrollPane.getViewport().setBackground(Style.UNUSED_TABLE_SPACE);
		scrollPane.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				JTable table = (JTable) ((JScrollPane) e.getSource()).getViewport().getView();
				table.getSelectionModel().clearSelection();
				table.removeEditor();
			}
		});
		add(scrollPane, BorderLayout.CENTER);
		add(categoriesAction(), BorderLayout.SOUTH);

		//

		// Ein bischen Hacky, aber es muss sichergestellt sein,
		// dass die Tabelle updated wird, wenn in der Kategorien-
		// Sicht eventuell ein neuer Plan erstellt wurde.
		this.addHierarchyListener(new HierarchyListener() {
			public void hierarchyChanged(HierarchyEvent e) {
				if (SheetsTable.this.isShowing()) {
					tableModel.update();
				}
			}
		});
	}

	public ValueModel getSelectedCategory() {
		return selectedCategory;
	}

	private JPanel categoriesAction() {
		JPanel panel = new JPanel(new BorderLayout());
		panel.add(createSheetsAction(), BorderLayout.EAST);
		return panel;
	}

	private JPanel createSheetsAction() {
		JPanel panel = new JPanel(new FlowLayout(SwingConstants.RIGHT));
		panel.add(createPrintButton());
		panel.add(createImportButton());
		panel.add(createExportButton());
		// panel.add(createMergeButton());
		return panel;
	}

	private Tournament getTournament() {
		return (Tournament) tournamentModel.getValue();
	}

	public UndoRedoManager getUndoRedoManager() {
		return ((MainView) SwingUtilities.getWindowAncestor(this)).getUndoRedoManager();
	}

	private JButton createExportButton() {
		final Action exportCategoryAction = new AbstractAction("Exportieren") {
			public void actionPerformed(ActionEvent e) {
				JFileChooser fileChooser = new JFileChooser();
				fileChooser.setCurrentDirectory(new File("."));
				fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				fileChooser.setDialogTitle("Kategorien exportieren (Verzeichnis wöhlen)");
				if (fileChooser.showDialog(SwingUtilities.getWindowAncestor(SheetsTable.this), "Hier speichern") == JFileChooser.APPROVE_OPTION) {
					File directory = fileChooser.getSelectedFile();
					for (int i = 0; i < table.getSelectedRows().length; i++) {
						Category category = tableModel.getCategory(table.getSelectedRows()[i]);
						Sheet sheet = new Sheet();
						sheet.category = category;
						sheet.sheetNo = tableModel.getSheetNo(table.getSelectedRows()[i]);
						File file = new File(directory, category.getName() + "_" + (sheet.sheetNo + 1) + ".page");
						FilePersistence.save(file, sheet);
					}
				}
			}
		};
		exportCategoryAction.setEnabled(table.getSelectedRows().length >= 1);
		table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				exportCategoryAction.setEnabled(table.getSelectedRows().length >= 1);
			}
		});
		return new JButton(exportCategoryAction);
	}

	private JButton createImportButton() {
		final Action importCategoryAction = new AbstractAction("Importieren...") {
			public void actionPerformed(ActionEvent e) {
				JFileChooser fileChooser = new JFileChooser();
				fileChooser.setCurrentDirectory(new File("."));
				fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				fileChooser.setDialogTitle("Seite Importieren");
				fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
					public boolean accept(File f) {
						return !f.isFile() || f.getName().endsWith(".page");
					}

					public String getDescription() {
						return "TRN (Turnier) (*.page)";
					}
				});
				if (fileChooser.showDialog(SheetsTable.this, "Importieren") == JFileChooser.APPROVE_OPTION) {
					try {
						Sheet sheet = FilePersistence.loadSheet(fileChooser.getSelectedFile());
						imprt(sheet);
					} catch (Exception x) {
						x.printStackTrace();
						JOptionPane
								.showMessageDialog(SheetsTable.this,
										"File kann nicht gelesen. Es ist entweder kein Seitenfile\noder von einer anderen Version geschrieben worden.");
					}
				}

			}
		};
		return new JButton(importCategoryAction);
	}

	private void imprt(Sheet sheet) {
		Category category = null;
		for (Category c : getTournament().getCategories()) {
			if (c.equals(sheet.category)) {
				category = c;
				break;
			}
		}
		if (category == null) {
			JOptionPane.showMessageDialog(SheetsTable.this, "Es wurde keine entsprechende Kategorie gefunden.\n"
					+ "Die Seite könnte aus einem anderen Turnier stammen.");
			return;
		}
		Plan plan = category.getPlan();
		Plan importedPlan = sheet.category.getPlan();
		for (Fight importedFight : importedPlan.getFights()) {
			if (category.getLayout().getSheetIndexForFight(importedFight) != sheet.sheetNo)
				continue;

			// find corresponding fight
			Fight fight = null;
			for (Fight f : plan.getFights()) {
				if (f.equals(importedFight)) {
					fight = f;
					break;
				}
			}
			if (fight != null) {
				for (int i = 0; i < fight.getFightEntries().size(); i++) {
					FightEntry entry = fight.getFightEntries().get(i);
					FightEntry importedEntry = importedFight.getFightEntries().get(i);
					if (entry.getFighterProvider() instanceof ModifiableFighterProvider) {
						ModifiableFighterProvider mfp = (ModifiableFighterProvider) entry.getFighterProvider();
						mfp.setFighter(importedEntry.getFighterProvider().getFighter());
					}
					entry.setScores(importedEntry.getScores());
					entry.setResult(importedEntry.getResult());
				}
			} else {
				FPExceptionHandler.instance().showWarning("Der Import enthält einen ungültigen Kampf.", "Fehler");
			}
		}
	}

	private JButton createPrintButton() {
		final Action printAction = new AbstractAction("Drucken") {
			public void actionPerformed(ActionEvent e) {
				java.util.List<Sheet> sheets = new ArrayList<Sheet>(table.getSelectedRowCount());
				for (int i = 0; i < table.getSelectedRowCount(); i++) {
					sheets.add(tableModel.getSheet(table.getSelectedRows()[i]));
				}
				new DrawingPrintable(getTournament(), sheets);
			}
		};
		printAction.setEnabled(table.getSelectedRowCount() > 0);
		table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				printAction.setEnabled(table.getSelectedRowCount() > 0);
			}
		});
		return new JButton(printAction);
	}

	//

	public void propertyChange(PropertyChangeEvent evt) {
		Tournament t = (Tournament) tournamentModel.getValue();
		tableModel.setCategories(t.getCategories());
	}

	//

	private static class SheetsTableModel extends AbstractTableModel implements ListDataListener {
		private GObservableList<Category> categories;

		private java.util.List<Sheet> sheets;

		public SheetsTableModel(Tournament tournament) {
			sheets = new ArrayList<Sheet>();
			if (tournament != null) {
				setCategories(tournament.getCategories());
			}
		}

		public void setCategories(GObservableList<Category> categories) {
			if (this.categories != null) {
				this.categories.removeListDataListener(this);
			}
			this.categories = categories;
			update();
			categories.addListDataListener(this);
		}

		public void update() {
			sheets.clear();
			for (Category category : categories) {
				if (category.getLayout() == null)
					continue;
				for (int i = 0; i < category.getLayout().getSheetCount(); i++) {
					Sheet sheet = new Sheet();
					sheet.category = category;
					sheet.sheetNo = i;
					sheets.add(sheet);
				}
			}
			fireTableDataChanged();
		}

		public int getColumnCount() {
			return 2;
		}

		public int getRowCount() {
			return sheets.size();
		}

		public Object getValueAt(int rowIndex, int columnIndex) {
			switch (columnIndex) {
			case 0:
				return ((Category) sheets.get(rowIndex).category).getDescription();
			case 1:
				return sheets.get(rowIndex).sheetNo + 1;
			default:
				return null;
			}
		}

		public Category getCategory(int rowIndex) {
			return (Category) sheets.get(rowIndex).category;
		}

		public int getSheetNo(int rowIndex) {
			return sheets.get(rowIndex).sheetNo;
		}

		public Sheet getSheet(int rowIndex) {
			return sheets.get(rowIndex);
		}

		// Listener

		@Override
		public String getColumnName(int column) {
			switch (column) {
			case 0:
				return "Kategorie";
			case 1:
				return "Blatt";
				// case 2: return "Status";
			default:
				return "";
			}
		}

		public void contentsChanged(ListDataEvent e) {
			update();
		}

		public void intervalAdded(ListDataEvent e) {
			update();
		}

		public void intervalRemoved(ListDataEvent e) {
			update();
		}

	}

}